package com.polaris.live.viewmodel.message

import android.content.Context
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import com.polaris.live.common.cacha.CacheUtil
import com.polaris.live.common.cacha.UserManager
import com.polaris.live.common.constant.AppConst
import com.polaris.live.common.constant.CommonConst
import com.polaris.live.common.mvvm.viewmodel.BaseViewModel
import com.polaris.live.common.network.request
import com.polaris.live.common.network.requestLoading
import com.polaris.live.common.network.state.ResultState
import com.polaris.live.common.util.JsonUtils
import com.polaris.live.common.util.ToastGravity
import com.polaris.live.constant.UserConst
import com.polaris.live.im.db.database.AppDatabase
import com.polaris.live.im.db.entity.GreetMessageEntity
import com.polaris.live.im.db.entity.MessageEntity
import com.polaris.live.im.manager.ImManager
import com.polaris.live.im.manager.ImSessionManager
import com.polaris.live.im.manager.TransformMessageListener
import com.polaris.live.im.sfs.COMMAND_SINGLE_MESSAGE
import com.polaris.live.im.sfs.EXT_FLAG_PUSH_MESSAGE
import com.polaris.live.im.sfs.MESSAGE_STATUS_SENDING
import com.polaris.live.im.sfs.MESSAGE_STATUS_TIMEOUT
import com.polaris.live.im.sfs.TYPE_MESSAGE_IMAGE
import com.polaris.live.im.sfs.TYPE_MESSAGE_TEXT
import com.polaris.live.im.sfs.bean.chat.SingleMessage
import com.polaris.live.im.sfs.bean.chat.ext.SingleMessageExtBean
import com.polaris.live.im.sfs.bean.chat.ext.SingleMessageParameterBean
import com.polaris.live.net.chatService
import com.polaris.live.net.liveService
import com.polaris.live.net.userService
import com.polaris.live.resp.back_resp.DisplayUserBean
import com.polaris.live.resp.back_resp.InfoOtherResp
import com.polaris.live.resp.back_resp.UploadUrlResp
import com.polaris.live.resp.back_resp.UserCoverResp
import com.polaris.live.resp.go_resp.InviteJoinPrepareRequest
import com.polaris.live.resp.go_resp.LiveInciteJoinPrepareResp
import com.polaris.live.resp.go_resp.MessageReadBean
import com.polaris.live.resp.go_resp.OtherUserIdBean
import com.polaris.live.resp.go_resp.PushDetailIdBean
import com.polaris.live.resp.go_resp.SettingModifyBean
import com.polaris.live.utils.BitwiseUtils
import com.polaris.live.utils.OtherUserCacheUtils
import com.polaris.live.utils.image.BitmapUtils
import com.polaris.live.utils.image.ImageUtils
import com.polaris.live.viewmodel.listeners.OnStreamLiveDataListener
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/**
 * MessageViewModel
 *
 * @author Created by 半仙 on 2023/9/4/004 21:30
 */
class MessageViewModel : BaseViewModel(), OnStreamLiveDataListener {

    /**
     * 获取用户的直播信息
     */
    override val userLiveLiveData = MutableLiveData<DisplayUserBean>()

    //关注
    val addFollowerLiveData = MutableLiveData<ResultState<Any>>()
    fun addFollower(otherId: Long) {
        requestLoading({ userService.addFollower(OtherUserIdBean(otherId)) }, addFollowerLiveData)
    }

    //获取更多数据
    val messageLiveData = MutableLiveData<List<MessageEntity>>()
    fun getMoreData(otherId: Long, timestamp: Long?) {
        viewModelScope.launch {
            try {
                val userId = UserManager.getUserId()
                val messageList = if (timestamp != null) {
                    AppDatabase.instance.messageDao()
                        .getMessagePage(userId, otherId, timestamp, AppConst.PAGE_SIZE)
                } else {
                    AppDatabase.instance.messageDao()
                        .getMessageFirstPage(userId, otherId, AppConst.PAGE_SIZE)
                }

                val finalMessageList = messageList.map {
                    if (it.state == MESSAGE_STATUS_SENDING) {
                        it.copy(
                            state = MESSAGE_STATUS_TIMEOUT
                        )
                    } else {
                        it
                    }
                }

                messageLiveData.value = finalMessageList
            } catch (t: Throwable) {
                t.printStackTrace()
            }
        }
    }

    //进来的时候先清除未读数
    fun clearUnreadCount(otherId: Long) {
        ImSessionManager.clearUnreadCount(otherId)
    }

    //获取用户信息
    val infoOtherLiveData = MutableLiveData<ResultState<InfoOtherResp>>()
    fun getInfoUser(id: Long, updateDb: Boolean = false, vararg type: Long) {
        val bitType = BitwiseUtils.bitwiseOperation(type)
        request({ userService.getInfoOther(id, bitType, UserConst.From.SINGLE) }, {
            infoOtherLiveData.value = ResultState.onAppSuccess(it)
            OtherUserCacheUtils.addUser(it, updateDb)
        }, {
            infoOtherLiveData.value = ResultState.onAppError(it)
            when (it.errCode) {
                CommonConst.ErrorCode.USER_LOGGED_OUT, //用户已注销
                CommonConst.ErrorCode.ACCOUNT_SHUT_DOWN-> {//该账号已经被关小黑屋
                    OtherUserCacheUtils.removeUser(id)
                }
            }
            ToastGravity.showGravity(it.errorMsg)
        })
    }

    fun deleteMessage(item: MessageEntity, otherId: Long) {
        viewModelScope.launch(Dispatchers.IO) {
            AppDatabase.instance.messageDao()
                .deleteByUserIdAndOtherIdAndMsgId(UserManager.getUserId(), otherId, item.msgId)
        }
    }

    fun sendTextMessage(
        context: Context,
        otherId: Long,
        text: String,
        pushDetailId: Long? = null,
    ) {
        val imEntity = SingleMessage(
            recipient = otherId,
            type = TYPE_MESSAGE_TEXT,
            content = text,
            payload = if (pushDetailId != null) JsonUtils.toJson(PushDetailIdBean(pushDetailId)) else null
        )
        ImManager.sendMessageWithAsync(context, COMMAND_SINGLE_MESSAGE, imEntity)
    }

    fun sendImageMessage(context: Context, otherId: Long, path: String) {
        val (width, height) = BitmapUtils.readBitmapSize(path) ?: (0 to 0)
        val ext = SingleMessageExtBean(
            imgWidth = width,
            imgHeight = height
        )

        //发送消息，需要先创建消息，然后再上传
        val singleMessage = SingleMessage(
            recipient = otherId,
            type = TYPE_MESSAGE_IMAGE,
            content = path,
            ext = JsonUtils.toJson(ext)
        )
        val parameter = SingleMessageParameterBean(
            localFilePath = path
        )

        ImManager.sendMessageWithAsync(
            context,
            COMMAND_SINGLE_MESSAGE,
            singleMessage,
            parameter,
            onTransform = { message ->
                val resp = ImageUtils.s3Upload(
                    path,
                    AppConst.UpLoad.MESSAGE_IMAGE
                )
                message.copy(
                    content = resp.path,
                    ext = resolveNewImageExt(ext, resp)
                )
            })
    }

    //消息重试
    fun sendRetry(context: Context, item: MessageEntity) {
        var block: TransformMessageListener? = null

        //图片消息需要先检查是否上传成功，如果是本地地址说明没有上传成功
        if (BitwiseUtils.isBitwise(item.type, TYPE_MESSAGE_IMAGE)
            && ImageUtils.isLocalPath(item.content)
        ) {
            block = TransformMessageListener { entity ->
                val resp = ImageUtils.s3Upload(
                    entity.content,
                    AppConst.UpLoad.MESSAGE_IMAGE
                )

                val ext = item.ext?.let { JsonUtils.fromJson<SingleMessageExtBean>(it) }

                entity.copy(
                    content = resp.path,
                    ext = ext?.let { resolveNewImageExt(it, resp) } ?: entity.ext
                )
            }
        }

        ImManager.retrySendMessageWithIO(context, item, block)
    }

    private fun resolveNewImageExt(ext: SingleMessageExtBean, resp: UploadUrlResp): String {
        return JsonUtils.toJson(
            ext.copy(
                imgWidth = resp.size?.first ?: ext.imgWidth,
                imgHeight = resp.size?.second ?: ext.imgHeight
            )
        )
    }

    //获取用户背景照
    val userCoverLiveData = MutableLiveData<ResultState<UserCoverResp>>()
    fun userCover() {
        request({ userService.coverPhotos() }, userCoverLiveData)
    }

    //消息已读
    fun messageRead(listGreetPushMessageFlag: List<MessageEntity>) {
        val readTime = CacheUtil.getServerTime()
        viewModelScope.launch(Dispatchers.IO) {
            listGreetPushMessageFlag.forEach { message ->
                message.payloadBean?.let { payload ->
                    //已读后告诉服务端
                    payload.pushDetailId?.let { id ->
                        val messageBean = MessageReadBean(id, readTime)
                        request({ chatService.messageRead(messageBean) }, {})
                    }
                    //告诉服务端后 修改本地标识
                    payload.flagGreetPushMessage = EXT_FLAG_PUSH_MESSAGE
                    val payloadString = JsonUtils.toJson(payload)
                    AppDatabase.instance.messageDao()
                        .updateFlagGreetPushMessage(message.msgId, payloadString)
                }
            }
        }
    }

    //获取双方是否有过打招呼消息
    val greetMessageLiveData = MutableLiveData<GreetMessageEntity?>()
    fun getGreetMessage(otherId: Long) {
        viewModelScope.launch {
            val findMessageByUserIdAndMsgId = AppDatabase.instance.greetMessageEntityDao()
                .findMessageByUserIdAndMsgId(UserManager.getUserId(), otherId)
            if (findMessageByUserIdAndMsgId != null) {
                greetMessageLiveData.value = findMessageByUserIdAndMsgId
            }
        }
    }

    //邀请消息预检查
    val inviteJoinPrepareLiveData = MutableLiveData<ResultState<LiveInciteJoinPrepareResp>>()
    fun inviteJoinPrepare(anchorId: Long, liveId: Long, roomId: String? = null) {
        requestLoading(
            { liveService.inviteJoinPrepare(InviteJoinPrepareRequest(anchorId, liveId, roomId)) },
            inviteJoinPrepareLiveData
        )
    }

    /**
     * 修改用户设置
     */
    fun settingModify(@UserConst.SettingType type: Int, state: Int) {
        requestLoading({ userService.settingModify(SettingModifyBean(type, state)) }, {
            when (type) {
                UserConst.UserSetting.LIVE_MODULE_SWITFCH -> {
                    UserManager.getUser().setting?.liveSwitch = state
                }
            }
        }, {
            ToastGravity.showGravity(it.errorMsg)
        })
    }
}